import time
import copy
import logging
from django.core.management import BaseCommand
from django.conf import settings
from common.es_core.es_interface import es_search_interface
from event_rule.cp.base_event_rule.rule_config import RULE_CONFIG as CP_RULE_CONFIG
from event_rule.dwc.base_event_rule.rule_config import RULE_CONFIG as DWC_RULE_CONFIG
from event_rule.utils import transform_event
from storage.rawdata.bypass_proxy import BypassProxyRawDataStorage
from preprocessor.adapter import EventPreprocessorAdapter

_LOGGER = logging.getLogger("reprocess_tag")

SYNC_RATIO = 10


class Command(BaseCommand):
    def __init__(self):
        super(Command, self).__init__()
        self.exclude_list_dct = {}
        self.sleep_time = 120
        self.to_check_index = settings.DWC_INDEX + settings.CP_INDEX
        self.exclude_list_dct = {index: {} for index in self.to_check_index}
        self.event_list = []
        self.event_list_limit = 50

    @staticmethod
    def roll_back_event_to_raw_data(index, event):
        if index in settings.CP_INDEX:
            rule_config = CP_RULE_CONFIG
        else:
            rule_config = DWC_RULE_CONFIG
        _id = event['_id']
        event_item = event['_source']
        event_id = event_item['_event_id']
        if event_id != _id[0:len(event_id)]:
            _LOGGER.info('index: {}, _id: {}, reprocess error'.format(index, _id))
            return False
        _id = _id[len(event_id + "_"):]
        raw_event = dict(_id=_id, _event_id=event_id, _event_time=event_item['_event_time'], _reprocess_tag=1)
        config = rule_config[event_id]
        for key, attr in config['values'].items():
            event_item_key = key if key.startswith('_') else '_'.join([event_id, key])
            if attr.get('required', True):
                raw_event[key] = event_item[event_item_key]
            else:
                if event_item_key in event_item:
                    raw_event[key] = event_item[event_item_key]
        return raw_event

    def reprocess_untag_event(self, index, user_id, register_time):
        default_size = 100
        decorate_field = "_account_active_days" if index in settings.CP_INDEX else "_active_days"
        query_dsl = {
            "query": {
                "bool": {
                    "filter": [
                        {"term": {"_user_id": user_id}}
                    ],
                    "must_not": [
                        {"exists": {"field": decorate_field}},
                        {"term": {"_event_id": "register"}}
                    ]
                }
            },
            "size": default_size
        }
        res_json = es_search_interface(index, query_dsl)
        if not res_json['hits']['total']:
            self.exclude_list_dct[index][user_id] = register_time
            print('index: {}, user_id: {}, no reprocess'.format(index, user_id))
            return
        print('index: {}, user_id: {}, reprocess count {}'.format(index, user_id, res_json['hits']['total']))
        if res_json['hits']['total'] > default_size:
            query_dsl['size'] = res_json['hits']['total']
            res_json = es_search_interface(index, query_dsl)
        handler_adapter = EventPreprocessorAdapter(index)
        for event in res_json['hits']['hits']:
            raw_event = self.roll_back_event_to_raw_data(index, event)
            if not raw_event:
                continue
            event = transform_event(raw_event, index)
            events = handler_adapter.handle(event)
            self.event_list += events

    def get_recently_register_user(self, index):
        time_delta = 86400
        estimate_register_user = 10000
        ts = int(time.time())
        exclude_user_id = list(self.exclude_list_dct[index].keys())
        query_dsl = {
            "query": {
                "bool": {
                    "filter": [
                        {"term": {"_event_id": "register"}},
                        {"range": {"_event_time": {"gte": ts - time_delta}}}
                    ],
                    "must_not": [
                        {"terms": {"_user_id": exclude_user_id}}
                    ]
                }
            },
            "size": estimate_register_user
        }
        res_json = es_search_interface(index, query_dsl)
        if res_json['hits']['total'] > estimate_register_user:
            query_dsl['size'] = res_json['hits']['total']
            res_json = es_search_interface(index, query_dsl)
        return {user['_source']['_user_id']: user['_source']['_event_time'] for user in res_json['hits']['hits']}

    def eliminate_old_user(self):
        ts = int(time.time())
        for index, exclude_dct in self.exclude_list_dct.items():
            exclude_dct_copy = copy.deepcopy(exclude_dct)
            for user_id, register_time in exclude_dct_copy.items():
                if register_time < ts:
                    exclude_dct.pop(user_id)

    def log(self, index, status='success'):
        for event in self.event_list:
            if status == 'success':
                _LOGGER.info(
                    'index: {}, user_id: {}, _id: {}, reprocess success'.format(index, event['_user_id'], event['_id']))
            else:
                _LOGGER.info(
                    'index: {}, user_id: {}, _id: {}, reprocess error'.format(index, event['_user_id'], event['_id']))

    def handle(self, **kwargs):
        while 1:
            for index in self.to_check_index:
                user_register = self.get_recently_register_user(index)
                print('index: {}, total_register_user: {}'.format(index, len(user_register)))
                time.sleep(5)
                storage = BypassProxyRawDataStorage(index)
                counter = 1
                for user_id, register_time in user_register.items():
                    try:
                        self.reprocess_untag_event(index, user_id, register_time)
                        print('index: {}, now on : {}/{}'.format(index, counter, len(user_register)))
                        counter += 1
                    except:
                        continue
                    if len(self.event_list) > self.event_list_limit:
                        storage.add_batch(self.event_list)
                        storage.execute_batch()
                        self.log(index)
                        self.event_list = []
                storage.add_batch(self.event_list)
                storage.execute_batch()
                self.log(index)
                self.event_list = []
            time.sleep(self.sleep_time)
            self.eliminate_old_user()
